#include "memory.h"

static MEMLIST listofblocks = NULL;
static int MEMLISTSIZE = 0;

MEMLIST list_insert(MEMLIST list,void* address, size_t length,char* file, int line)
{
	MEMDATA* m = (MEMDATA*)malloc(sizeof(MEMDATA));
	m->address = address;
	m->length  = length;
	m->file    = file;
	m->line    = line;
	m->next = list;
	MEMLISTSIZE++;
	return m;
}

MEMLIST list_remove(MEMLIST list,void* address)
{
	MEMDATA* current = list;
	MEMDATA* prev;
	while((current->address != address)&&(current!=NULL)) {
		prev = current;
		current = current->next;
	}
	if(current == NULL) return list;
	
	if(current == list) {
		list = current->next;
	} else {
		prev->next = current->next;
	}
	free(current);
	MEMLISTSIZE--;
	return list;	
}

MEMLIST list_update(MEMLIST list,void* address,void* addr,size_t length, char* file, int line)
{
	MEMDATA* current = list;
	while((current!=NULL)&&(current->address != address)) {
		current = current->next;
	}
	if(current == NULL) return list;
	current->address = addr;
	current->length = length;
	current->file = file;
	current->line = line;	
	return list;	
}

void list_print(MEMLIST list)
{
	if(MEMLISTSIZE != 0)
		printf("\nPossible Memory Leaks\n---------------------\n");
	while(list != NULL) {
		printf("[%x]\t %d bytes, allocated in %s:%d\n",
			(int)list->address,list->length,list->file,list->line);
		list = list->next;
	}
}

void* jcalloc(size_t nmemb, size_t size, char* file, int line) {
	void* address = calloc(nmemb,size);
	listofblocks = list_insert(listofblocks,address,size,file,line);
	return address;
}

void* jmalloc(size_t size,char* file, int line) {
	void* address = malloc(size);
	listofblocks = list_insert(listofblocks,address,size,file,line);
	return address;
}

void* jrealloc(void* address, size_t size, char* file, int line) {
	void* addr = realloc(address,size);
	listofblocks = list_update(listofblocks,address,addr,size,file,line);
	return addr;
}

void  jfree(void *ptr) {
	listofblocks = list_remove(listofblocks,ptr);
	free(ptr);
}

void jterminate(int exitcode) {
	list_print(listofblocks);
	exit(exitcode);
}
